#include <GL/glut.h>
#include <cstdio>
#define _USE_MATH_DEFINES
#include <cmath>

#include "opengldraw.h"
#include "parabolathrow.h"

void init();
void display();
void reshape(int newWidth, int newHeight);
void keyboard(unsigned char key,int x,int y);
void specialKeyboard(int key, int, int);
void update(int);

static const int WINDOW_WIDTH   = 800;
static const int WINDOW_HEIGHT  = 600;
static const char* TITLE = "Angry Ball";

//y-Wert
static const float  GROUND = 50.0f;
static const int    TOWERPOS = 600;
static const int    TOWERSIZE = 70;

static const unsigned UPDATETIME = 1000/20;

//TestVariablen;
static ParabolaThrow pThrow;
static Cannon cannon;

static float angle = 45.0f;
static float speed = 75.0f;

static Tower tower(TOWERPOS, GROUND, TOWERSIZE);

static Explosion ex(300, 300, 30);

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
	glutCreateWindow(TITLE);

	init();

	glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialKeyboard);

    glutTimerFunc(UPDATETIME, update, 0);

	glutMainLoop();

}

void init()
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
    //Just 2D. No Depthbuffer needed.
    glDisable(GL_DEPTH_TEST);
    gluOrtho2D(0.0, WINDOW_WIDTH, 0.0, WINDOW_HEIGHT); //(0,0) is now in the lower left corner

}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
	
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


    drawTower(tower);
    drawExplosion(ex);
    drawBall(pThrow.ball(), 255, 255, 255);
    drawCannon(cannon, angle);




    //Bottom Line
    glPushMatrix();
        glColor3f(1.0f, 0.0f, 0.0f);
        glLineWidth(5.0f);
        glBegin(GL_LINES);
            glVertex2f(0.0f, GROUND);
            glVertex2f(WINDOW_WIDTH, GROUND);
        glEnd();
    glPopMatrix();

    glutSwapBuffers();
}

void reshape(int newWidth,int newHeight)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0, 0, newWidth, newHeight);
    gluOrtho2D(0.0, newWidth, 0.0, newHeight);

    glMatrixMode(GL_MODELVIEW);
}


void keyboard(unsigned char key, int, int)
{
    printf("pressed %c\n", key);

    switch(key)
    {
    case 32:
        pThrow.throwBall((cosf(angle * M_PI /180) * 60.0f) + cannon.getX(), (sinf(angle * M_PI/180) * 60.0f) + cannon.getY(), speed, angle);
        printf("%f/%f\n", pThrow.ball().getX(), pThrow.ball().getY());
        break;
    case 'r':
        tower.reset();
        pThrow.reset();
        break;
    default:
        break;
    }
    fflush(stdout);
}

void specialKeyboard(int key, int, int)
{
    switch(key)
    {
    case GLUT_KEY_UP:
        //angle should not be greater than 90
        if((angle + 1.0f) <= 90)
        {
            angle += 1.0f;
            printf("angle: %f\n", angle);
        }
        break;
    case GLUT_KEY_DOWN:
        //angle should not be smaller than 0
        if((angle - 1.0f) >= 0)
        {
            angle -= 1.0f;
            printf("angle: %f\n", angle);
        }
        break;
    case GLUT_KEY_LEFT:
        if(speed  >= 20)
        speed -= 1.0f;
        printf("speed: %f\n", speed);
        break;
    case GLUT_KEY_RIGHT:
        if(speed <= 120)
        speed += 1.0f;
        printf("speed: %f\n", speed);
        break;
    default:
        break;
    }
    fflush(stdout);
}

void update(int)
{
    if(tower.everthingDead())
        tower.reset();

    pThrow.move();
    const Ball& ball = pThrow.ball();
    //Check if Ball hit Ground or the right border
    if(ball.getY() < GROUND || ball.getX() >= WINDOW_WIDTH)
        pThrow.reset();
    else if(ball.getX() >= 500) // Start checking for Collision if Ball.x is grater than 500
    {
        for(unsigned i = 0; i <= 10; ++i)
        {
            Target& t = tower.getTarget(i);
            if(t.isInside(ball))
            {

                t.decreaseHealth();
                if(t.health() == 0) {
                    ex.setX(t.getX() + t.getWidth() / 2);
                    ex.setY(t.getY() + t.getHeight() / 2);
                    ex.resetTimer();
                    drawExplosion(ex);
                }
                pThrow.reset();
            }
        }
    }
    glutPostRedisplay();
    glutTimerFunc(UPDATETIME, update, 0);
}

